package handlers

import (
	"context"
	"errors"
	"game-server/game-grpc"
	"game-server/interfaces"
	"game-server/message"
	"log"
	"math/rand"
	"pb/protocol"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pb "pb/proto"
)

// 匹配管理器，用于跟踪玩家的匹配状态
var (
	// 正在匹配的玩家映射表 playerID -> matchInfo
	matchingPlayers      = make(map[uint32]*matchInfo)
	matchingPlayersMutex sync.RWMutex
)

// 匹配信息
type matchInfo struct {
	playerID   uint32
	matchType  int32
	cancelFunc context.CancelFunc // 用于取消匹配请求
	startTime  time.Time          // 匹配开始时间
}

func HandlerMatch(client interfaces.IClient, msg message.IMessage) error {
	req := &pb.MatchReq{}
	if err := proto.Unmarshal(msg.GetData(), req); err != nil {
		log.Printf("解析匹配请求失败: %v", err)
		return err
	}

	playerID := client.GetID()

	// 检查玩家是否已经在匹配中
	matchingPlayersMutex.RLock()
	_, alreadyMatching := matchingPlayers[uint32(playerID)]
	matchingPlayersMutex.RUnlock()

	if alreadyMatching {
		return sendMatchResponse(client, 0, "您已经在匹配中")
	}

	formations, err := GetPlayerFormations(playerID)
	if err != nil {
		log.Printf("获取阵容失败: %v", err)
		return sendMatchResponse(client, 0, "获取阵容失败")
	}

	// 检查阵容是否已初始化
	if len(formations) == 0 {
		return sendMatchResponse(client, 0, "没有初始化阵容")
	}

	// 检查阵容是否已满
	formationMap := make(map[int32]int32)
	for _, val := range formations {
		if val.HeroId == 0 {
			return sendMatchResponse(client, 0, "阵容未满")
		}
		formationMap[int32(val.Position)] = int32(val.HeroId)
	}

	// 先给客户端发送匹配开始的响应
	if err := sendMatchResponse(client, 1, ""); err != nil {
		return err
	}

	// 创建可取消的上下文
	matchCtx, cancelFunc := context.WithTimeout(context.Background(), 60*time.Second)

	// 将玩家加入匹配队列
	matchingPlayersMutex.Lock()
	matchingPlayers[uint32(playerID)] = &matchInfo{
		playerID:   uint32(playerID),
		matchType:  req.MatchType,
		cancelFunc: cancelFunc,
		startTime:  time.Now(),
	}
	matchingPlayersMutex.Unlock()

	log.Printf("玩家 %d 开始匹配，类型: %d", playerID, req.MatchType)

	// 异步发送匹配请求
	go func() {
		defer func() {
			// 无论如何，确保在函数结束时移除玩家的匹配状态
			matchingPlayersMutex.Lock()
			delete(matchingPlayers, uint32(playerID))
			matchingPlayersMutex.Unlock()

			// 取消上下文
			cancelFunc()
		}()

		matchClient := game_grpc.GetMatchClient()
		if matchClient == nil {
			log.Printf("匹配客户端未初始化")
			sendFailedMatchRes(client, 0, "服务暂时不可用")
			return
		}

		// 发送gRPC匹配请求

		res, err := matchClient.Match(matchCtx, &pb.GrpcMatchReq{
			PlayerId:  int32(playerID),
			MatchType: req.MatchType,
			HeroInfo:  formationMap,
			// 随机一个，可以根据实际情况调整
			Capacity: int32(100 + rand.Intn(100)),
		})

		// 处理错误情况
		if err != nil {
			// 检查是否是上下文取消导致的错误
			if errors.Is(matchCtx.Err(), context.Canceled) {
				log.Printf("玩家 %d 的匹配请求被取消", playerID)
				return // 玩家主动取消，不需要发送失败消息
			}

			// 检查是否是超时错误
			if errors.Is(matchCtx.Err(), context.DeadlineExceeded) || status.Code(err) == codes.DeadlineExceeded {
				log.Printf("玩家 %d 的匹配请求超时", playerID)
				sendFailedMatchRes(client, 0, "匹配超时，请重试")
				return
			}

			log.Printf("发送匹配请求失败: %v", err)
			sendFailedMatchRes(client, 0, "匹配服务异常")
			return
		}

		// 处理匹配结果
		if res.State != 1 {
			log.Printf("匹配失败: %s", res.Msg)
			sendFailedMatchRes(client, 0, res.Msg)
			return
		}

		// 匹配成功，处理房间分配
		log.Printf("玩家 %d 匹配成功，分配到房间 %d", playerID, res.RoomId)
		// 通知客户端匹配成功
		sendMatchSuccessRes(client, res) // 2表示匹配成功
	}()

	return nil
}

// 取消匹配
func HandlerCancelMatch(client interfaces.IClient, msg message.IMessage) error {
	req := &pb.MatchCancelReq{}
	if err := proto.Unmarshal(msg.GetData(), req); err != nil {
		log.Printf("解析取消匹配请求失败: %v", err)
		return err
	}

	playerID := client.GetID()

	// 检查玩家是否在匹配中
	matchingPlayersMutex.RLock()
	matchInfo, found := matchingPlayers[uint32(playerID)]
	matchingPlayersMutex.RUnlock()

	if !found {
		log.Printf("玩家 %d 尝试取消匹配，但未找到匹配记录", playerID)
		return sendCancelMatchResponse(client, 0, "您不在匹配队列中")
	}

	// 检查匹配类型是否一致
	if matchInfo.matchType != req.MatchType {
		log.Printf("玩家 %d 尝试取消类型 %d 的匹配，但实际在匹配类型 %d",
			playerID, req.MatchType, matchInfo.matchType)
		return sendCancelMatchResponse(client, 0, "匹配类型不匹配")
	}

	// 取消匹配
	matchInfo.cancelFunc() // 这会触发上下文取消

	// 从匹配列表中移除
	matchingPlayersMutex.Lock()
	delete(matchingPlayers, uint32(playerID))
	matchingPlayersMutex.Unlock()

	log.Printf("玩家 %d 取消了类型 %d 的匹配，匹配持续了 %.2f 秒",
		playerID, req.MatchType, time.Since(matchInfo.startTime).Seconds())

	// 发送取消成功响应
	return sendCancelMatchResponse(client, 1, "")
}

// 发送匹配响应
func sendFailedMatchRes(client interfaces.IClient, state int32, errMsg string) {
	err := sendMatchResponse(client, state, errMsg)
	if err != nil {
		log.Printf("发送匹配响应失败: %v", err)
	}
}

// 发送匹配成功响应
func sendMatchSuccessRes(client interfaces.IClient, res *pb.GrpcMatchRes) {
	matchRes := &pb.MatchRes{
		State:  res.State, // 0=失败，1=匹配中，2=匹配成功
		ErrMsg: res.Msg,
		RoomId: res.RoomId,
	}
	err := sendMatchRes(client, matchRes)
	if err != nil {
		log.Printf("发送匹配响应失败: %v", err)
	}

}

// 发送匹配响应
func sendMatchResponse(client interfaces.IClient, state int32, errMsg string) error {
	matchRes := &pb.MatchRes{
		State:  state, // 0=失败，1=匹配中，2=匹配成功
		ErrMsg: errMsg,
	}

	return sendMatchRes(client, matchRes)
}

func sendMatchRes(client interfaces.IClient, res *pb.MatchRes) error {
	data, err := proto.Marshal(res)
	if err != nil {
		log.Printf("序列化匹配响应错误: %v", err)
		return err
	}

	responseMsg := message.NewMessage(protocol.S_C_MATCH_RES, data)
	if err := client.SendMessage(responseMsg.GetData()); err != nil {
		log.Printf("发送匹配响应错误: %v", err)
		return err
	}
	return nil
}

// 发送取消匹配响应
func sendCancelMatchResponse(client interfaces.IClient, state int32, msg string) error {
	cancelRes := &pb.MatchCancelRes{
		State: state, // 1=成功，0=失败
	}

	data, err := proto.Marshal(cancelRes)
	if err != nil {
		log.Printf("序列化取消匹配响应错误: %v", err)
		return err
	}

	responseMsg := message.NewMessage(protocol.S_C_MATCH_CANCEL_RES, data)
	if err := client.SendMessage(responseMsg.GetData()); err != nil {
		log.Printf("发送取消匹配响应错误: %v", err)
		return err
	}

	return nil
}
